/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		lsa tc.cpp
 * PURPOSE:		LSA (Local Security Authority) object types
 */

namespace Lsa
{

namespace Specific
{
	PCWSTR Policy[DESC_SPECIFIC_SIZE] = 
	{
		L"Query Local Info",
		L"Query Audit Info",
		L"Get Private Info",
		L"Trust Control",
		L"Create Account",
		L"Create Secret",
		L"Create Privilege",
		L"Set Default Quota",
		L"Set Audit Req.",
		L"Audit Log Control",
		L"Server Control",
		L"Lookup Names",
		L"Notify"
	};

	PCWSTR Account[DESC_SPECIFIC_SIZE] =
	{
		L"View",
		L"Adjust Privileges",
		L"Adjust Quotas",
		L"Adjust System Access"
	};

	//for Secret, use ntapi QueryModify

}//namespace Specific

class LsaObject : public Win32::OpaqueAccessNtSecDescObject
{
	auto_refct<Lsa::LsaPolicy> Policy;
	HANDLE Handle;

public:
	LsaObject(auto_refct<Lsa::LsaPolicy> &Policy, HANDLE Handle) :
		OpaqueAccessNtSecDescObject(SD_FLAG_NO_SYNCHRONIZE),
		Policy(Policy),
		Handle(Handle)
	{}

	virtual LONG QuerySecDesc(SECURITY_INFORMATION Si, OUT auto_szpod<SECURITY_DESCRIPTOR_RELATIVE> &Sd) override
	{
		auto_szpod<SECURITY_DESCRIPTOR_RELATIVE, Lsa::LsaHeap> Buff;

		NTSTATUS Status = LsaQuerySecurityObject(Handle, Si, Buff.assign_indirect());

		if(Status == STATUS_ACCESS_DENIED)
			return ERROR_ACCESS_DENIED;

		RaiseOnNtError(Status);

		Sd = Buff;

		return ERROR_SUCCESS;
	}

	virtual void SetSecDesc(SECURITY_DESCRIPTOR const *Sd, SECURITY_INFORMATION Si) override
	{
		RaiseOnNtError(LsaSetSecurityObject(Handle, Si, Sd));
	}

	~LsaObject()
	{
		LsaClose(Handle);
	}
};

//policy as a securable object, as opposed to the connection (LsaPolicy)
class Policy : public LsaObject
{
public:
	Policy(auto_refct<Lsa::LsaPolicy> &Policy) :
		LsaObject(Policy, Policy->Handle),
		Object(Specific::Policy, L"LSA Policy")
	{}
};

class Account : public LsaObject
{
public:
	Account(auto_refct<Lsa::LsaPolicy> &Policy, HANDLE Handle, PCWSTR Name) :
		LsaObject(Policy, Handle),
		Object(Specific::Account, Name)
	{}

	static Account *CreateNew(auto_refct<Lsa::LsaPolicy> &Policy, SID *Sid, UCHAR Privileges, PCWSTR Name)
	{
		HANDLE Handle;

		RaiseOnNtError(LsaOpenAccount(Policy->Handle, Sid, MAXIMUM_ALLOWED | StandardPrivilegedRights(Privileges), &Handle));

		return new Account(Policy, Handle, Name);
	}

	static Account *CreateNewByTextSid(auto_refct<Lsa::LsaPolicy> &Policy, PCWSTR TextSid, UCHAR Privileges)
	{
		auto_szpod<SID> Sid = TextToSid(TextSid);

		return CreateNew(Policy, Sid, Privileges, TextSid);
	}

	static Account *CreateNewByName(auto_refct<Lsa::LsaPolicy> &Policy, PCWSTR Name, UCHAR Privileges)
	{
		Lsa::LsaLookupNameWorkItem Wi(Name, Policy, NULL);
		Wi.Work();

		return CreateNew(Policy, Wi.Result, Privileges, Name);
	}
};

class Secret : public LsaObject
{
public:
	Secret(auto_refct<Lsa::LsaPolicy> &Policy, HANDLE Handle, PCWSTR Name) :
		LsaObject(Policy, Handle),
		Object(Ntapi::Specific::QueryModify, Name)
	{}

	static Secret *CreateNew(auto_refct<Lsa::LsaPolicy> &Policy, PCWSTR Name, UCHAR Privileges)
	{
		HANDLE Handle;
		UNICODE_STRING Name_UCS;

		RtlInitUnicodeString(&Name_UCS, const_cast<PWSTR>(Name));

		RaiseOnNtError(LsaOpenSecret(Policy->Handle, &Name_UCS, MAXIMUM_ALLOWED | StandardPrivilegedRights(Privileges), &Handle));

		return new Secret(Policy, Handle, Name);
	}
};

}//namespace Lsa